package com.ybwh.springboot2.common.mail;

import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import freemarker.template.Configuration;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.util.CollectionUtils;

import javax.mail.internet.MimeMessage;
import java.io.File;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 电子邮件发送工具
 * </p>
 *
 * @author fanbeibei
 * @version V1.0
 * @since 2019/9/10 11:05
 */
@Slf4j
@AllArgsConstructor
public class EmailSender {

    private JavaMailSender javaMailSender;
    /**
     * 默认发送人
     */
    private String defalutFrom;
    /**
     * 默认的接收人,逗号隔开
     */
    private String defaultTo;


    /**
     * 异步发送逻辑
     */
    private static ListeningExecutorService executorService = MoreExecutors.listeningDecorator(new ThreadPoolExecutor(1, 10, 50, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100)));

    public interface MailSendCallback {
        void afterSend();
    }


    /**
     * 发送普通文本邮件
     *
     * @param subject     邮件标题
     * @param content     邮件内容
     * @param attachments 附件,无则传null。 附件名称->附件
     */
    public void sendTextMail(String subject, String content, Map<String, File> attachments) {
        String[] to = defaultTo.split("[\\,\\;]");
        sendTextMail(defalutFrom, to, subject, content, attachments);
    }

    /**
     * 异步发送普通文本邮件
     *
     * @param subject     邮件标题
     * @param content     邮件内容
     * @param attachments 附件,无则传null。 附件名称->附件
     * @param callback    异步发送回调逻辑
     */
    public void sendTextMailAsync(String subject, String content, Map<String, File> attachments, MailSendCallback callback) {
        ListenableFuture future = executorService.submit(() -> {
            sendTextMail(subject, content, attachments);
        });

        if (null != callback) {
            future.addListener(() -> {
                callback.afterSend();
            }, executorService);
        }
    }


    /**
     * 发送普通文本邮件
     *
     * @param from        发件方地址
     * @param to          收件方邮箱
     * @param subject     邮件标题
     * @param content     邮件内容
     * @param attachments 附件,无则传null。  附件名称->附件
     */
    public void sendTextMail(String from, String[] to, String subject, String content, Map<String, File> attachments) {
        Preconditions.checkArgument(null != from, "param  from is null");
        Preconditions.checkArgument(ArrayUtils.isNotEmpty(to), "param  to is null");
        Preconditions.checkArgument(StringUtils.isNotBlank(subject), "param  subject is null");
        Preconditions.checkArgument(StringUtils.isNotBlank(content), "param  content is null");

        try {
            MimeMessage mimeMessage = javaMailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
            //发送地址
            helper.setFrom(from);
            helper.setTo(to);

            helper.setSubject(subject);
            //重点，默认为false，显示原始html代码，无效果
            helper.setText(content, false);

            if (!CollectionUtils.isEmpty(attachments)) {
                for (Map.Entry<String, File> en : attachments.entrySet()) {
                    helper.addAttachment(en.getKey(), en.getValue());
                }
            }

            javaMailSender.send(mimeMessage);
        } catch (Exception e) {
            log.error("", e);
        }
    }

    /**
     * 异步发送普通文本邮件
     *
     * @param from        发件方地址
     * @param to          收件方邮箱
     * @param subject     邮件标题
     * @param content     邮件内容
     * @param attachments 附件,无则传null。  附件名称->附件
     * @param callback    异步发送回调逻辑
     */
    public void sendTextMailAsync(String from, String[] to, String subject, String content, Map<String, File> attachments, MailSendCallback callback) {
        ListenableFuture future = executorService.submit(() -> {
            sendTextMail(from, to, subject, content, attachments);
        });

        if (null != callback) {
            future.addListener(() -> {
                callback.afterSend();
            }, executorService);
        }
    }

    /**
     * 发送模板邮件
     *
     * @param subject        邮件标题
     * @param templateFile   模板文件名称(classpath:mail-template目录下的文件)
     * @param templateParams 模板参数
     * @param attachments    附件,无则传null。 附件名称->附件
     */
    public void sendTemplateMail(String subject,
                                 Map<String/*参数名称*/, Object/*参数值*/> templateParams, String templateFile,
                                 Map<String, File> attachments) {
        String[] to = defaultTo.split("[\\,\\;]");
        sendTemplateMail(defalutFrom, to, subject, templateParams, templateFile, attachments);
    }


    /**
     * 异步发送模板邮件
     *
     * @param subject        邮件标题
     * @param templateFile   模板文件名称(classpath:mail-template目录下的文件)
     * @param templateParams 模板参数
     * @param attachments    附件,无则传null。 附件名称->附件
     * @param callback       异步发送回调逻辑
     */
    public void sendTemplateMailAsync(String subject,
                                      Map<String/*参数名称*/, Object/*参数值*/> templateParams, String templateFile,
                                      Map<String, File> attachments, MailSendCallback callback) {
        ListenableFuture future = executorService.submit(() -> {
            sendTemplateMail(subject, templateParams, templateFile, attachments);
        });

        if (null != callback) {
            future.addListener(() -> {
                callback.afterSend();
            }, executorService);
        }
    }

    /**
     * 发送模板邮件
     *
     * @param from           发件方地址
     * @param to             收件方邮箱
     * @param subject        邮件标题
     * @param templateFile   模板文件名称(classpath:mail-template目录下的文件)
     * @param templateParams 模板参数
     * @param attachments    附件,无则传null。 附件名称->附件
     */
    public void sendTemplateMail(String from, String[] to, String subject,
                                 Map<String/*参数名称*/, Object/*参数值*/> templateParams, String templateFile,
                                 Map<String, File> attachments) {

        Preconditions.checkArgument(null != from, "param  from is null");
        Preconditions.checkArgument(ArrayUtils.isNotEmpty(to), "param  to is null");
        Preconditions.checkArgument(StringUtils.isNotBlank(subject), "param  subject is null");
        Preconditions.checkArgument(StringUtils.isNotBlank(templateFile), "param  templateFile is null");
        try {


            MimeMessage mimeMessage = javaMailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
            //发送地址
            helper.setFrom(from);
            helper.setTo(to);

            //模板处理
            Configuration configuration = new Configuration(Configuration.VERSION_2_3_28);
            configuration.setClassForTemplateLoading(this.getClass(), "/mail-template");
            if (null == templateParams) {
                templateParams = Collections.emptyMap();
            }
            String html = FreeMarkerTemplateUtils.processTemplateIntoString(configuration.getTemplate(templateFile), templateParams);
            helper.setSubject(subject);
            //重点，默认为false，显示原始html代码，无效果
            helper.setText(html, true);

            if (!CollectionUtils.isEmpty(attachments)) {
                for (Map.Entry<String, File> en : attachments.entrySet()) {
                    helper.addAttachment(en.getKey(), en.getValue());
                }
            }

            javaMailSender.send(mimeMessage);
        } catch (Exception e) {
            log.error("", e);
        }
    }


    /**
     * 异步发送模板邮件
     *
     * @param from           发件方地址
     * @param to             收件方邮箱
     * @param subject        邮件标题
     * @param templateFile   模板文件名称(classpath:mail-template目录下的文件)
     * @param templateParams 模板参数
     * @param attachments    附件,无则传null。 附件名称->附件
     * @param callback       异步发送回调逻辑
     */
    public void sendTemplateMailAsync(String from, String[] to, String subject,
                                      Map<String/*参数名称*/, Object/*参数值*/> templateParams, String templateFile,
                                      Map<String, File> attachments, MailSendCallback callback) {
        ListenableFuture future = executorService.submit(() -> {
            sendTemplateMail(from, to, subject, templateParams, templateFile, attachments);
        });

        if (null != callback) {
            future.addListener(() -> {
                callback.afterSend();
            }, executorService);
        }
    }

    public static void main(String[] args) {
//        String[] arr = "11;333;444;333;88".split("[\\,\\;]");
//        System.out.println(arr);
    }

}
